﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Data.Common;
using System.Linq;
using SharpDB.Entity;
using SharpDB.SPI;
using SharpDB;
using System.Collections.Concurrent;
using System.Text.RegularExpressions;
using System.Data.SqlClient;
using System.Reflection;
using SharpDB.DDTekOracle;

namespace SharpDB.DDTekOracle
{
    public partial class OracleDB : IDB
    {
        /// <summary>
        ///  OracleDB 实例
        /// </summary>
        /// <param name="host">IP或服务器名称</param>
        /// <param name="port">端口号</param>
        /// <param name="uid">用户名</param>
        /// <param name="pwd">密码</param>
        /// <param name="serviceName">服务名(数据库名)</param>
        /// <param name="customOperaTingTables">自定义要操作的所有表名（默认所有）：因Oracle有时在创建数据库时，会自动创建大量 乱七八糟的表(名)，如 DEF$_LOB 。。。 </param>
        public OracleDB(string host, int port, string uid, string pwd, string serviceName, List<string> customOperaTingTables = null)
            : this(
                  string.Format("Host={0};Port={1};User ID={2};Password={3};Service Name={4};PERSIST SECURITY INFO=True;", host, port, uid, pwd, serviceName),
                  customOperaTingTables)
        {

        }

        /// <summary>
        /// OracleDB 实例
        /// </summary>
        /// <param name="connectionString">数据库连接字符串</param>
        /// <param name="customOperaTingTables">自定义要操作的所有表名（默认所有）：因Oracle有时在创建数据库时，会自动创建大量 乱七八糟的表(名)，如 DEF$_LOB 。。。 </param>
        public OracleDB(string connectionString, List<string> customOperaTingTables = null)
        {
            InitDDTek();
            this.ConnectionString = connectionString;
            //Oracle 使用时 表名 大写
            if (customOperaTingTables != null)
            {
                this.CustomOperaTingTables = customOperaTingTables.Select(t => t.Trim().ToUpper()).ToList();
            }         
            this.Info = new DBInfo(this);
        }


        static void InitDDTek()
        {
            // 框架加载dll失败后执行，手动加载dll
            AppDomain.CurrentDomain.AssemblyResolve += (sender, senderArgs) =>
            {
                // 当前程序集
                var executingAssembly = Assembly.GetExecutingAssembly();
                // 当前程序集名称
                var assemblyName = new AssemblyName(executingAssembly.FullName).Name;
                // dll名称
                var dllName = new AssemblyName(senderArgs.Name).Name;
                // 待加载dll路径，指向当前程序集资源文件中dll路径。* 根据程序结构调整，使其正确指向dll
                var dllUri = assemblyName + "." + dllName + ".dll";
                // 加载dll
                using (var resourceStream = executingAssembly.GetManifestResourceStream(dllUri))
                {
                    var assemblyData = new Byte[resourceStream.Length];
                    resourceStream.Read(assemblyData, 0, assemblyData.Length);
                    return Assembly.Load(assemblyData); //加载dll
                }
            };
        }



        /// <summary>
        /// 数据库连接字符串
        /// </summary>
        public string ConnectionString
        {
            get; private set;
        }

        /// <summary>
        /// 数据库相关信息
        /// </summary>
        public DBInfo Info
        {
            get; private set;
        }

        /// <summary>
        /// 自定义要操作的所有表名（默认所有）：因Oracle有时在创建数据库时，会自动创建大量 乱七八糟的表(名)，如 DEF$_LOB 。。。 
        /// </summary>
        public List<string> CustomOperaTingTables
        {
            get;
            set;
        } = new List<string>();


        /// <summary>
        /// 定时器 查询表结构的 间隔（单位：毫秒）
        /// </summary>
        public double TimerInterval
        {
            get
            {
                if (Info != null && Info.timer != null)
                    return Info.timer.Interval;
                else
                    return 0;
            }
        }

        /// <summary>
        /// 等待命令执行所需的时间（以秒为单位）。 默认值为 30 秒。
        /// </summary>
        private int _CmdTimeOut = 30;
        public int CmdTimeOut
        {
            set { _CmdTimeOut = value; }
            get { return _CmdTimeOut; }
        }


        /// <summary>
        /// 异常前 执行的事件。
        /// 意义/作用：在报异常前记录 执行的Sql命令参数 ，以及异常信息，类似于 飞机黑匣子。
        /// </summary>

        public event EventHandler<OnErrorEventArgs> OnError;

        
        
        private void PrepareCommand(DbCommand cmd, DbConnection conn, DbTransaction trans, string cmdText, OracleParam[] cmdParms, int timeout, CommandType cmdType = CommandType.Text)
        {
            if (conn.State != ConnectionState.Open)
                conn.Open();
            cmd.Connection = conn;
            cmd.CommandText = cmdText;
            if (trans != null)
                cmd.Transaction = trans;
            cmd.CommandType = cmdType;
            if (timeout > 0)
            {
                cmd.CommandTimeout = timeout;
            }
            else
            {
                cmd.CommandTimeout = CmdTimeOut;
            }
            if (cmdParms != null && cmdParms.Length > 0)
            {
                for (int j = 0; j < cmdParms.Length; j++)
                {
                    var parameter = cmdParms[j].GetParameter();
                    if ((parameter.Direction == ParameterDirection.InputOutput
                        || parameter.Direction == ParameterDirection.Input)
                        && (parameter.Value == null))
                    {
                        parameter.Value = DBNull.Value;
                    }
                    cmd.Parameters.Add(parameter);
                }
            }
        }


    }
}
